#include "camera.h"
#include <qdebug.h>
#include "MyError.h"
#include "fileUtils.h"


Camera::Camera(QObject* parent): QObject(parent) {
	IGXFactory::GetInstance().Init();
}

Camera::~Camera() {
	try {
		if (!m_streamPtr.IsNull()) {
			//发送停采指令
			m_objDevicePtr->GetRemoteFeatureControl()->GetCommandFeature("AcquisitionStop")->Execute();
			m_streamPtr->StopGrab();
			m_streamPtr->UnregisterCaptureCallback();
			m_streamPtr->Close();
			m_objDevicePtr->Close();
		}
	} catch (const CGalaxyException& e) {
		qCritical() << e.what();
	}
	IGXFactory::GetInstance().Uninit();
}

void Camera::listCamera(QStringList& cameraList) {
	//使用USB相机时必须要先枚举设备，否则相机打不开
	GxIAPICPP::gxdeviceinfo_vector vectorDeviceInfo;
	IGXFactory::GetInstance().UpdateAllDeviceList(1000, vectorDeviceInfo);
	for (int i = 0; i < vectorDeviceInfo.size(); i++) {
		qDebug() << vectorDeviceInfo[i].GetMAC();
		cameraList.push_back(vectorDeviceInfo[i].GetMAC().c_str());
	}
}

bool Camera::open(QString num) {
	if (num.isEmpty()) {
		QStringList cameraList;
		listCamera(cameraList);
		if (cameraList.size() > 0) {
			m_name = cameraList[0];
		} else {
			throw MyError(MyErrorType::CAMERA_LIVE_ERROR);
		}
	}
	try {
		GxIAPICPP::gxstring _num(m_name.toStdString().c_str());
		//重置设备，防止程序重启后设备打开失败
		IGXFactory::GetInstance().GigEResetDevice(_num, GX_MANUFACTURER_SPECIFIC_RECONNECT);
		//通过MAC地址打开设备
		m_objDevicePtr = IGXFactory::GetInstance().OpenDeviceByMAC(_num, GX_ACCESS_EXCLUSIVE);
		if (!m_objDevicePtr.IsNull()) {
			m_streamPtr = m_objDevicePtr->OpenStream(0);
			//注册回调函数，用于采集图像
			m_streamPtr->GetFeatureControl()->GetEnumFeature("StreamBufferHandlingMode")->SetValue("OldestFirst");
			m_streamPtr->RegisterCaptureCallback(this, NULL);
			//设置图像缓存区大小
			m_streamPtr->SetAcqusitionBufferNumber(100);
			//获取相机参数控制对象
			CGXFeatureControlPointer featureControlPointer = m_objDevicePtr->GetRemoteFeatureControl();
			//提高网络相机的采集性能, 设置方法参考以下代码（目前只有千兆网系列相机支持设置最优包长）
			GX_DEVICE_CLASS_LIST objDeviceClass = m_objDevicePtr->GetDeviceInfo().GetDeviceClass();
			if (GX_DEVICE_CLASS_GEV == objDeviceClass) {
				if (true == featureControlPointer->IsImplemented("GevSCPSPacketSize")) {
					//获取当前网络环境的最优包长值
					int nPacketSize = m_streamPtr->GetOptimalPacketSize();
					//将最优包长值设置为当前设备的流通道包长值
					featureControlPointer->GetIntFeature("GevSCPSPacketSize")->SetValue(nPacketSize);
				}
			}
		}
	} catch (const CGalaxyException& e) {
		qCritical() << e.what();
		throw MyError(MyErrorType::CAMERA_NOT_CONNECT);
	} catch (const exception& e) {
		qCritical() << e.what();
		throw MyError(MyErrorType::CAMERA_NOT_CONNECT);
	} catch (...) {
		qCritical() << "UNKNOW_ERROR";
		throw MyError(MyErrorType::UNKNOW_ERROR);
	}
	return !m_streamPtr.IsNull();
}

bool Camera::isOpened() {
	return !m_streamPtr.IsNull();
}

void Camera::setParams(const CameraConfig& config) {
	QStringList errorMsg;
	try {
		if (isOpened()) {
			//设置帧数
			if (config.frameCount > 0) {
				m_frameCount = config.frameCount;
			}
			CGXFeatureControlPointer featureControlPointer = m_objDevicePtr->GetRemoteFeatureControl();
			//设置曝光
			try {
				if (config.exposure > 0) {
					featureControlPointer->GetEnumFeature("ExposureAuto")->SetValue("Off");
					featureControlPointer->GetFloatFeature("ExposureTime")->SetValue(config.exposure);
				}
			} catch (...) {
				errorMsg.push_back("曝光时间设置失败！");
			}
			//设置增益
			try {
				if (config.gain > 0) {
					featureControlPointer->GetEnumFeature("GainSelector")->SetValue("AnalogAll");
					featureControlPointer->GetEnumFeature("GainAuto")->SetValue("Off");
					featureControlPointer->GetFloatFeature("Gain")->SetValue(config.gain);
				}
			} catch (...) {
				errorMsg.push_back("增益设置失败！");
			}
			//设置白平衡
			try {
				//设置白平衡R
				if (config.whiteBalanceRed > 0) {
					featureControlPointer->GetEnumFeature("BalanceRatioSelector")->SetValue("Red");
					featureControlPointer->GetFloatFeature("BalanceRatio")->SetValue(config.whiteBalanceRed);
				}
				//设置白平衡G
				if (config.whiteBalanceGreen > 0) {
					featureControlPointer->GetEnumFeature("BalanceRatioSelector")->SetValue("Green");
					featureControlPointer->GetFloatFeature("BalanceRatio")->SetValue(config.whiteBalanceGreen);
				}
				//设置白平衡B
				if (config.whiteBalanceBlue > 0) {
					//设置白平衡
					featureControlPointer->GetEnumFeature("BalanceRatioSelector")->SetValue("Blue");
					featureControlPointer->GetFloatFeature("BalanceRatio")->SetValue(config.whiteBalanceBlue);
				}
			} catch (...) {
				errorMsg.push_back("白平衡设置失败！");
			}
			//设置帧率
			if (config.fps > 0) {
				try {
					//开启帧率设置模式（否则设置帧率无效）
					featureControlPointer->GetEnumFeature("AcquisitionFrameRateMode")->SetValue("On");
					featureControlPointer->GetFloatFeature("AcquisitionFrameRate")->SetValue(config.fps);
				} catch (...) {
					errorMsg.push_back("帧率设置失败！");
				}
			}
			//设置每帧的宽度
			if (config.offsetX >= 0 && config.offsetY >= 0 && config.frameWidth > 0 && config.frameHeight > 0) {
				qDebug() << "当前帧宽度: " << config.frameWidth;
				qDebug() << "当前帧高度: " << config.frameHeight;
				try {
					setROI(config.offsetX, config.offsetY, config.frameWidth, config.frameHeight);
				} catch (...) {
					qDebug() << "ROI区域设置失败！";
					errorMsg.push_back("ROI区域设置失败！");
				}
			}
		}
	} catch (const CGalaxyException& e) {
		qCritical() << e.what();
		errorMsg.push_back(e.what());
	} catch (const std::exception& e) {
		qCritical() << e.what();
		errorMsg.push_back(e.what());
	} catch (...) {
		errorMsg.push_back("未处理的错误");
	}
	if (errorMsg.size() > 0) {
		throw MyError(MyErrorType::CAMERA_SET_PARAMS_ERROR);
	}
}

void Camera::setROI(int x, int y, int width, int height) {
	if (isOpened() && width > 0 && height > 0 && x >= 0 && y >= 0) {
		try {
			CGXFeatureControlPointer featureControlPointer = m_objDevicePtr->GetRemoteFeatureControl();
			featureControlPointer->GetIntFeature("Width")->SetValue(width);
			featureControlPointer->GetIntFeature("Height")->SetValue(height);
			//设置传感器的起始位置X
			featureControlPointer->GetIntFeature("OffsetX")->SetValue(x);
			//设置传感器坐标Y
			featureControlPointer->GetIntFeature("OffsetY")->SetValue(y);
		} catch (const CGalaxyException& e) {
			qCritical() << e.what();
			throw MyError(MyErrorType::CAMERA_ROI_SET_ERROR);
		} catch (const std::exception& e) {
			qCritical() << e.what();
			throw MyError(MyErrorType::CAMERA_ROI_SET_ERROR);
		} catch (...) {
			throw MyError(MyErrorType::CAMERA_ROI_SET_ERROR);
		}
	}
}

void Camera::startLive() {
	if (isOpened()) {
		try {
			//启动相机
			m_streamPtr->StartGrab();
			//发送开采指令
			m_objDevicePtr->GetRemoteFeatureControl()->GetCommandFeature("AcquisitionStart")->Execute();
		} catch (const CGalaxyException& e) {
			qCritical() << "发送开采指令出错:" << e.what() << endl;
			throw MyError(MyErrorType::CAMERA_LIVE_ERROR);
		}
	} else {
		qCritical() << "相机未连接...";
		throw MyError(MyErrorType::CAMERA_NOT_CONNECT);
	}
}

void Camera::stopLive() {
	if (isOpened()) {
		try {
			//发送停采指令
			m_objDevicePtr->GetRemoteFeatureControl()->GetCommandFeature("AcquisitionStop")->Execute();
			m_streamPtr->StopGrab();
		} catch (const CGalaxyException& e) {
			qCritical() << e.what();
			throw MyError(MyErrorType::CAMERA_LIVE_ERROR);
		}
	} else {
		qCritical() << "相机未连接...";
		throw MyError(MyErrorType::CAMERA_NOT_CONNECT);
	}
}

void Camera::startCollect(int frameCount) {
	if (!m_objDevicePtr.IsNull()) {
		// 初始化图片计数器和图片缓存
		m_frameCount = frameCount;
		qDebug()<<"要采集的帧数m_frameCount= "<<m_frameCount;
		//m_frameCount = 1;
		//m_frameNum = 0;
		m_collectFlag = true;
	} else {
		qCritical() << "相机未连接...";
		throw MyError(MyErrorType::CAMERA_NOT_CONNECT);
	}
}

void Camera::stopCollect() { 
	m_collectFlag = false;
}

bool Camera::isCollectStart() const {
	return m_collectFlag;
}

void Camera::DoOnImageCaptured(CImageDataPointer& objImageDataPointer, void* pUserParam) {
	try {
		qDebug() << "DoOnIMG0...";
		// 图像数据转为Mat
		void* pRGB24Buffer = objImageDataPointer->ConvertToRGB24(GX_BIT_0_7, GX_RAW2RGB_NEIGHBOUR, true);
		qDebug() << "DoOnIMG1...";
		cv::Mat frame;
		// 指定高度、宽度和类型来分配内存
		frame.create(objImageDataPointer->GetHeight(), objImageDataPointer->GetWidth(), CV_8UC3);
		memcpy(frame.data, pRGB24Buffer, (objImageDataPointer->GetHeight()) * (objImageDataPointer->GetWidth()) * 3);
		// 图像旋转
		cv::rotate(frame, frame, cv::ROTATE_90_COUNTERCLOCKWISE);
		if (m_collectFlag) {
			//qDebug() << "当前采集图像帧数: " << m_frameNum;
			if (m_frameNum < m_frameCount) {
				emit frameUpload(m_frameNum, frame);
				std::string nums = std::to_string(m_frameNum);
				std::stringstream ss;
				ss << std::setw(2) << std::setfill('0') << nums;
				string savename = "./data/" + ss.str() + ".bmp";
				//cv::imwrite(savename, frame);

				m_frameNum++;
			} else {
				m_collectFlag = false;
				qDebug() << "grab over m_collectFlag=" << m_collectFlag << endl;
				m_frameNum = 0;
				stopLive();
			}
		} else {
			// 显示图像
			if (TimeUtils::getTimeGen() - m_lastFrameTime > 50) {
				m_lastFrameTime = TimeUtils::getTimeGen();
				emit frameReady(frame);
			}
		}
	} catch (const CGalaxyException& e) {
		qCritical() << e.what();
	} catch (...) {
		qCritical() << "ERROR!";
	}
}

